package com.han.bom;

import java.util.ArrayList;
import java.util.Date;

/**
 * The ExamResponse class represents the "test paper" for each student. Contains a copy of the exam
 * and the answer of the student to each question. Also automates the "closing" of the exam due to
 * time constraints. 
 * 
 * @author Ric Janus Sapasap
 * @since JDK 1.7
 * @version 1.0
 * @see Answer
 * @see Exam
 * @see ExamThread
 */
public class ExamResponse {
	private String examResponseID;
	private ArrayList<Answer> answers;
	private Exam exam;
	private boolean active;
	private Date dateTaken;
	private double grade;
	private boolean submitted;
	
	public Date getDateTaken() {
		return dateTaken;
	}

	public void setDateTaken(Date dateTaken) {
		this.dateTaken = dateTaken;
	}

	/**
	 * Sole Constructor, instantiates an exam response for a student
	 * generates an ExamReponseID based on the ExamID and StudentID 
	 * 
	 * @param exam an instance of the Exam class
	 * @param studentID the studentID of the student creating the exam
	 * @see Exam
	 * @see Student
	 */
	public ExamResponse(Exam exam,String studentID, ArrayList<Answer> answers) {
		super();
		this.exam = exam;
		this.answers = answers;
		String id = "T"+((exam instanceof RealExam)?((RealExam) exam).getTimesActivated():((PracticeExam) exam).getTimesTaken());
		
		this.examResponseID = exam.getExamID()+studentID+id;
		if(exam instanceof RealExam){
			setActive(true);			
		}
		this.grade=0;
	}

	/* (non-Javadoc)
	 * returns the hash code for this object
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((examResponseID == null) ? 0 : examResponseID.hashCode());
		return result;
	}



	/* (non-Javadoc)
	 * compares this object to the specified parameter
	 * @see java.lang.Object#equals(java.lang.Object)
	 * @return returns true if the examResponseID is equal
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ExamResponse other = (ExamResponse) obj;
		if (examResponseID == null) {
			if (other.examResponseID != null)
				return false;
		} else if (!examResponseID.equals(other.examResponseID))
			return false;
		return true;
	}



	/* (non-Javadoc)
	 * returns a string representation of this object
	 * @see java.lang.Object#toString()
	 * @return the string representation
	 */
	@Override
	public String toString() {
		return "ExamResponse [examResponseID=" + examResponseID + ", answers="
				+ answers + ", exam=" + exam + "]";
	}

	/**
	 * returns the ID that uniquely identifies this ExamResponse 
	 * 
	 * @return the examResponseID
	 */
	public String getExamResponseID() {
		return examResponseID;
	}



	/**
	 * Sets the ExamResponseID to the parameter
	 * 
	 * @param examResponseID the new ExamResponseID
	 */
	public void setExamResponseID(String examResponseID) {
		this.examResponseID = examResponseID;
	}

	/**
	 * gets the ArrayList of Answers submitted by the Student
	 * 
	 * @return the ArrayList of Answers
	 * @see Answer
	 * @see ArrayList
	 */
	public ArrayList<Answer> getAnswers() {
		return answers;
	}

	/**
	 * sets this instance's answers to the specified ArrayList
	 * 
	 * @param answers the ArrayList of Answers
	 * @see Answer
	 * @see ArrayList
	 */
	public void setAnswers(ArrayList<Answer> answers) {
		this.answers = answers;
	}
	
	/**
	 * computes the score for the specified exam given the answers given by the student
	 * 
	 * @return the score of the student
	 */
	public int computeScore(){
		int score = 0;
		
		if(answers==null){
			return -1;
		}
		
		for(Answer ans: answers){
			if(ans.isCorrect()){
				score++;
			}
		}
		
		this.setGrade(100.0*((double)score/this.getExam().getQuestions().size()));
		
		return score;
	}

	/**
	 * gets the Exam instance of this object
	 * 
	 * @return the exam instance
	 */
	public Exam getExam() {
		return exam;
	}

	/**
	 * sets this ExamResponses' exam attribute to the parameter
	 * 
	 * @param exam the exam replacement
	 */
	public void setExam(Exam exam) {
		this.exam = exam;
	}
	
	/**
	 * Adds an Answer instance to the ArrayList of Answers
	 * 
	 * @param question the Question instance
	 * @param answer the string representation of the answer
	 */
	public boolean addAnswer(Question question, String answer){
		boolean ret = this.exam instanceof RealExam?this.active:true;
		
		if(ret){
			if(question!=null&&answer!=null){
			
				Answer temp = new Answer(question, answer);
				
				if(!this.answers.contains(temp)){
					this.answers.add(temp);
				}
				else{
					return false;
				}
			}
		}
		
		return ret;
	}

	/**
	 * sets this ExamResponse's active status to the parameter
	 * used by the ExamThread instance to automatically disable adding and changing answers when the duration is over
	 * 
	 * @param active new value of boolean active
	 */
	public void setActive(boolean active) {
		this.active = active;
	}

	/**
	 * checks if this ExamResponse is active, it is inactive before the start of the exam and after the duration has lapsed
	 * 
	 * @return returns true if this exam is active, false otherwise
	 */
	public boolean isActive() {
		return active;
	}

	public void setGrade(double grade) {
		this.grade = grade;
	}

	public double getGrade() {
		return grade;
	}
	
	public String getStudentID(){
		int index1 = this.getExamResponseID().indexOf("S");
		int index2 = this.getExamResponseID().indexOf("T");
		String studentId = this.getExamResponseID().substring(index1, index2);
		return studentId;
	}
	
	public String getExamID(){
		return this.getExam().getExamID();
	}

	public void setSubmitted(boolean submitted) {
		this.submitted = submitted;
	}

	public boolean isSubmitted() {
		return submitted;
	}
	
}
